﻿using Mapster;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using RuoVea.DynamicWebApi;
using RuoVea.ExCache;
using RuoVea.ExDto;
using RuoVea.ExEnum;
using RuoVea.ExSugar;
using RuoVea.ExSugar.Entity;
using RuoVea.ExUtil;
using RuoVea.OmiApi.Dict.Entitys;
using RuoVea.OmiApi.Dict.Language;
using RuoVea.OmiApi.Dict.Service.Dto;
using SqlSugar;
using System.ComponentModel;
using System.Text.RegularExpressions;

namespace RuoVea.OmiApi.Dict.Service;
/// <summary>
/// 字典类型服务 🔷
/// </summary>
[ApiExplorerSettings(GroupName = "system")]
public class SysDictTypeService : IApplicationService
{
    private readonly SugarRepository<SysDictType> _thisRepository;
    private readonly SugarRepository<SysDictValue> _dictValueRepository;
    private readonly SysDictValueService _sysDictValueService;

    /// <summary>
    /// 字典类型服务构造函数
    /// </summary>
    /// <param name="thisRepository">字典类型仓储</param>
    /// <param name="sysDictValueService">字典值服务</param>
    /// <param name="dictValueRepository">字典值服务</param>
    public SysDictTypeService(SugarRepository<SysDictType> thisRepository, SysDictValueService sysDictValueService, SugarRepository<SysDictValue> dictValueRepository )
    {
        _thisRepository = thisRepository;
        _sysDictValueService = sysDictValueService;
        _dictValueRepository = dictValueRepository;
    }

    /// <summary>
    /// 分页查询字典类型🔹
    /// </summary>
    /// <param name="data">查询参数</param>
    /// <returns>分页结果</returns>
    public virtual async Task<PageResult<SysDictTypeDto>> GetPagesAsync([FromQuery] SysDictTypeParam data)
    {
        // 规范化编码参数（转换为大写）
        if (!string.IsNullOrEmpty(data.Code))
        {
            data.Code = data.Code.Trim().ToUpper();
        }

        var hasCode = !string.IsNullOrEmpty(data.Code);
        var hasName = !string.IsNullOrEmpty(data.Name?.Trim());

        var query = await _thisRepository.AsQueryable()
            .Where(u => u.IsDelete == IsDelete.N)
            .WhereIF(data.SysFlag.HasValue, u => u.SysFlag == data.SysFlag)
            .WhereIF(data.IsDisable.HasValue, u => u.IsDisable==data.IsDisable)
            .WhereIF(hasCode, u => u.Code.Contains(data.Code))
            .WhereIF(hasName, u => u.Name.Contains(data.Name))
            .OrderBy(u => u.Sort)
            .ToPageAsync<SysDictType, SysDictTypeDto>(data.PageNo, data.PageSize);
        return query;
    }

    /// <summary>
    /// 根据ID获取字典类型详情🔹
    /// </summary>
    /// <param name="data">ID参数</param>
    /// <returns>字典类型详情</returns>
    public virtual async Task<SysDictTypeDto> GetDataAsync([FromQuery] EntityBaseId data)
    {
        var model = await _thisRepository.AsQueryable().Where(x => x.Id == data.Id).FirstAsync();
        return model.Adapt<SysDictTypeDto>();
    }

    /// <summary>
    /// 获取字典类型列表 🔖
    /// </summary>
    /// <returns>字典类型列表</returns>
    [DisplayName("获取字典类型列表")]
    public async Task<List<SysDictType>> GetList()
    {
        return await _thisRepository.AsQueryable().OrderBy(u => new { u.Sort, u.Code }).ToListAsync();
    }

    /// <summary>
    /// 获取所有字典类型列表🔹
    /// </summary>
    /// <returns>字典类型列表</returns>
    [NonAction]
    public async Task<List<SysDictType>> GetDataList()
    {
        return await _thisRepository.GetListAsync(u => u.IsDelete == IsDelete.N);
    }

    /// <summary>
    /// 新增字典类型🔹
    /// </summary>
    /// <param name="data">字典类型数据</param>
    /// <returns>操作结果</returns>
    public virtual async Task<bool> AddDataAsync(SysDictTypeDto data)
    {
        // 规范化编码（转换为大写）
        data.Code = data.Code?.Trim().ToUpper();

        // 校验编码格式
        if (!ValidateCodeFormat(data.Code, out string errorMessage))
        {
            throw new ArgumentException(errorMessage);
        }

        var isExist = await _thisRepository.IsAnyAsync(u => u.Name == data.Name || u.Code == data.Code);

        if (isExist) throw new ArgumentException(i18n.error_message_dict_type_exists);

        var dictType = data.Adapt<SysDictType>();

        return await _thisRepository.InsertAsync(dictType);
    }

    /// <summary>
    /// 更新字典类型🔹
    /// </summary>
    /// <param name="data">字典类型数据</param>
    /// <returns></returns>
    public virtual async Task UpdateDataAsync(SysDictTypeDto data)
    {
        // 规范化编码（转换为大写）
        data.Code = data.Code?.Trim().ToUpper();

        // 校验编码格式
        if (!ValidateCodeFormat(data.Code, out string errorMessage))
        {
            throw new ArgumentException(errorMessage);
        }

        var isExist = await _thisRepository.IsAnyAsync(u => u.Id == data.Id);
        if (!isExist) throw new ArgumentException(i18n.error_message_dict_type_not_found);

        // 排除自己并且判断与其他是否相同
        isExist = await _thisRepository.IsAnyAsync(u => (u.Name == data.Name || u.Code == data.Code) && u.Id != data.Id);
        if (isExist) throw new ArgumentException(i18n.error_message_dict_type_exists);

        var dictType = data.Adapt<SysDictType>();
        await _thisRepository.UpdateAsync(dictType);
    }

    /// <summary>
    /// 删除字典类型🔹
    /// </summary>
    /// <param name="data">ID参数</param>
    /// <returns></returns>
    [HttpDelete]
    public virtual async Task DeleteDataAsync([FromBody] EntityBaseId data)
    {
        var dictType = await _thisRepository.GetFirstAsync(u => u.Id == data.Id);
        if (dictType == null) throw new ArgumentException(i18n.error_message_dict_type_not_found);

        // 检查是否为系统内置字典类型
        if (dictType.SysFlag == YesOrNot.Y)
        {
            throw new InvalidOperationException(i18n.error_message_system_dict_cannot_delete);
        }

        // 检查该字典类型下是否有字典值
        var hasDictValues = await _dictValueRepository.IsAnyAsync(u => u.TypeId == data.Id && u.IsDelete == IsDelete.N);
        if (hasDictValues)
        {
            throw new InvalidOperationException(i18n.error_message_dict_type_has_values_cannot_delete);
        }

        if (dictType.IsDelete == IsDelete.Y)
            await _thisRepository.DeleteByIdAsync(data.Id);
        else
        {
            dictType.IsDelete = IsDelete.Y;
            await _thisRepository.UpdateAsync(dictType);
        }
        CacheFactery.Cache.Del($"{CacheConst.KeyDict}{dictType.Code}");
    }

    /// <summary>
    /// 根据字典类型编码获取字典值下拉列表🔹
    /// </summary>
    /// <param name="data">下拉框参数</param>
    /// <returns>字典值列表</returns>
    [AllowAnonymous]
    public async Task<List<SysDictValue>> GetDictTypeDropDown([FromQuery] DropDownDictTypeInput data)
    {
        // 规范化编码（转换为大写）
        data.Code = data.Code?.Trim().ToUpper();

        var dictType = await _thisRepository.GetFirstAsync(u => u.Code == data.Code && u.IsDelete == IsDelete.N && u.IsDisable == YesOrNot.N);
        if (dictType == null) throw new ArgumentException(i18n.error_message_dict_type_disabled);
        return await _sysDictValueService.GetDictValueListByDictTypeId(dictType.Id);
    }

    /// <summary>
    /// 更新字典类型状态🔹
    /// </summary>
    /// <param name="data">状态参数</param>
    /// <returns></returns>
    [HttpPut]
    public async Task ChangeStatus(ChangeStateDictTypeInput data)
    {
        var dictType = await _thisRepository.GetFirstAsync(u => u.Id == data.Id && u.IsDelete == IsDelete.N);
        if (dictType == null) throw new ArgumentException(i18n.error_message_dict_type_not_found);

        if (!data.IsDisable.IsDefined<YesOrNot>())
            throw new ArgumentException(i18n.error_message_invalid_status);

        dictType.IsDisable = data.IsDisable;
        dictType.IsDelete = IsDelete.N;
        await _thisRepository.UpdateAsync(dictType);

        CacheFactery.Cache.Del($"{CacheConst.KeyDict}{dictType.Code}");
    }

    /// <summary>
    /// 获取所有字典类型及其值集合 🔹
    /// </summary>
    /// <returns>字典集合</returns>
    [DisplayName("获取所有字典类型及其值集合")]
    public async Task<dynamic> GetAllDictList()
    {
        var ds = await _thisRepository.AsQueryable()
            .InnerJoin<SysDictValue>((u, a) => u.Id == a.TypeId)
            .Where((u, a) => u.IsDelete == IsDelete.N && a.IsDelete == IsDelete.N && a.IsDisable == YesOrNot.N)
            .Select((u, a) => new { TypeCode = u.Code, a.Code, a.Value, a.Remark, a.Sort })
            .ToListAsync();
        return ds.OrderBy(u => u.Sort).GroupBy(u => u.TypeCode).ToDictionary(u => u.Key, u => u);
    }

    #region 内部方法
    /// <summary>
    /// 根据编码查询字典类型🔹
    /// </summary>
    /// <param name="code">字典类型编码</param>
    /// <returns>字典类型详情</returns>
    [NonAction]
    public virtual async Task<SysDictTypeDto> GetTypeByCodeAsync(string code)
    {
        // 规范化编码（转换为大写）
        code = code?.Trim().ToUpper();

        var model = await _thisRepository.AsQueryable().Where(x => x.Code == code).FirstAsync();
        return model.Adapt<SysDictTypeDto>();
    }

    /// <summary>
    /// 根据编码查询字典类型及其值🔹
    /// </summary>
    /// <param name="code">字典类型编码</param>
    /// <returns>字典类型及值</returns>
    [NonAction]
    public virtual async Task<SysDictType> GetTypeAndDataByCodeAsync(string code)
    {
        // 规范化编码（转换为大写）
        code = code?.Trim().ToUpper();

        var model = await _thisRepository.AsQueryable().Includes(x => x.Children).Where(x => x.Code == code).FirstAsync();
        return model;
    }

    /// <summary>
    /// 根据字典类型编码获取字典值列表🔹
    /// </summary>
    /// <param name="typeCode">字典类型编码</param>
    /// <returns>字典值列表</returns>
    [NonAction]
    public async Task<List<SysDictValue>> GetDictValuesByTypeCodeAsync(string typeCode)
    {
        // 规范化编码（转换为大写）
        typeCode = typeCode?.Trim().ToUpper();

        var dictType = await _thisRepository.GetFirstAsync(u => u.Code == typeCode && u.IsDelete == IsDelete.N && u.IsDisable == YesOrNot.N);
        if (dictType == null) throw new ArgumentException(i18n.error_message_dict_type_disabled);
        return await _sysDictValueService.GetDictValueListByDictTypeId(dictType.Id);
    }

    /// <summary>
    /// 根据编码查询字典类型（带缓存）🔹
    /// </summary>
    /// <param name="code">字典类型编码</param>
    /// <returns>字典类型详情</returns>
    [NonAction]
    public virtual async Task<SysDictTypeDto> GetTypeByCodeCaChe(string code)
    {
        // 规范化编码（转换为大写）
        code = code?.Trim().ToUpper();

        var dictTypeList = CacheFactery.Cache.Read<SysDictTypeDto>($"{CacheConst.KeyDict}DictType:{code}");
        if (dictTypeList == null)
        {
            dictTypeList = await GetTypeByCodeAsync(code);
            if (dictTypeList == null) return dictTypeList;
            else
            {
                CacheFactery.Cache.Write($"{CacheConst.KeyDict}DictType:{code}", dictTypeList);
                return dictTypeList;
            }
        }
        return dictTypeList;
    }
    /// <summary>
    /// 根据编码列表查询字典类型及其值（带缓存）🔹
    /// </summary>
    /// <param name="codes">字典类型编码列表</param>
    /// <returns>字典类型及值列表</returns>
    [NonAction]
    public virtual async Task<List<SysDictType>> GetTypesAndDataByCodeCaChe(params string[] codes)
    {
        if (codes == null || codes.Length == 0)
            return new List<SysDictType>();

        // 规范化编码（转换为大写并去重）
        var normalizedCodes = codes
            .Where(code => !string.IsNullOrWhiteSpace(code))
            .Select(code => code.Trim().ToUpper())
            .Distinct()
            .ToList();

        if (normalizedCodes.Count == 0)
            return new List<SysDictType>();

        var result = new List<SysDictType>();
        var codesToQuery = new List<string>();

        // 首先尝试从缓存中获取
        foreach (var code in normalizedCodes)
        {
            var cacheKey = $"{CacheConst.KeyDict}DictTypeValue:{code}";
            var cachedItem = CacheFactery.Cache.Read<SysDictType>(cacheKey);

            if (cachedItem != null)
            {
                result.Add(cachedItem);
            }
            else
            {
                codesToQuery.Add(code);
            }
        }

        // 如果所有数据都在缓存中，直接返回
        if (codesToQuery.Count == 0)
            return result;

        // 查询缓存中不存在的数据
        var dbResults = await GetTypesAndDataByCodeAsync(codesToQuery.ToArray());

        // 将查询结果存入缓存并添加到返回列表
        foreach (var item in dbResults)
        {
            var cacheKey = $"{CacheConst.KeyDict}DictTypeValue:{item.Code?.ToUpper()}";
            CacheFactery.Cache.Write(cacheKey, item);
            result.Add(item);
        }

        return result;
    }
    /// <summary>
    /// 根据编码查询字典类型及其值（带缓存）🔹
    /// </summary>
    /// <param name="code">字典类型编码</param>
    /// <returns>字典类型及值</returns>
    [NonAction]
    public virtual async Task<SysDictType> GetTypeAndDataByCodeCaChe(string code)
    {
        // 规范化编码（转换为大写）
        code = code?.Trim().ToUpper();

        var dictTypeList = CacheFactery.Cache.Read<SysDictType>($"{CacheConst.KeyDict}DictTypeValue:{code}");
        if (dictTypeList == null)
        {
            dictTypeList = await GetTypeAndDataByCodeAsync(code);
            if (dictTypeList == null) return dictTypeList;
            else
            {
                CacheFactery.Cache.Write($"{CacheConst.KeyDict}DictTypeValue:{code}", dictTypeList);
                return dictTypeList;
            }
        }
        return dictTypeList;
    }
    /// <summary>
    /// 根据编码列表查询字典类型及其值🔹
    /// </summary>
    /// <param name="codes">字典类型编码列表</param>
    /// <returns>字典类型及值列表</returns>
    [NonAction]
    public virtual async Task<List<SysDictType>> GetTypesAndDataByCodeAsync(params string[] codes)
    {
        if (codes == null || codes.Length == 0)
            return new List<SysDictType>();

        // 规范化编码（转换为大写并去重）
        var normalizedCodes = codes
            .Where(code => !string.IsNullOrWhiteSpace(code))
            .Select(code => code.Trim().ToUpper())
            .Distinct()
            .ToList();

        if (normalizedCodes.Count == 0)
            return new List<SysDictType>();

        var models = await _thisRepository.AsQueryable()
            .Includes(x => x.Children)
            .Where(x => normalizedCodes.Contains(x.Code))
            .ToListAsync();

        return models;
    }
    /// <summary>
    /// 根据字典类型编码获取字典值列表（带缓存）🔹
    /// </summary>
    /// <param name="typeCode">字典类型编码</param>
    /// <returns>字典值列表</returns>
    [NonAction]
    public async Task<List<SysDictValue>> GetDictValuesByTypeCodeCaChe(string typeCode)
    {
        // 规范化编码（转换为大写）
        typeCode = typeCode?.Trim().ToUpper();

        var dictDataList = CacheFactery.Cache.Read<List<SysDictValue>>($"{CacheConst.KeyDict}DictDatas:{typeCode}");
        if (dictDataList == null)
        {
            dictDataList = await GetDictValuesByTypeCodeAsync(typeCode);
            if (dictDataList == null) return dictDataList;
            else
            {
                CacheFactery.Cache.Write($"{CacheConst.KeyDict}DictDatas:{typeCode}", dictDataList);
                return dictDataList;
            }
        }
        return dictDataList;
    }

    /// <summary>
    /// 校验字典类型编码格式
    /// </summary>
    [NonAction]
    public bool ValidateCodeFormat(string code, out string errorMessage)
    {
        errorMessage = string.Empty;

        if (string.IsNullOrWhiteSpace(code))
        {
            errorMessage = i18n.error_message_code_empty;
            return false;
        }

        if (!Regex.IsMatch(code, @"^[A-Z]"))
        {
            errorMessage = i18n.error_message_code_start_with_uppercase;
            return false;
        }

        if (!Regex.IsMatch(code, @"^[A-Z0-9_]+$"))
        {
            errorMessage = i18n.error_message_code_invalid_chars;
            return false;
        }

        if (code.Length > 50)
        {
            errorMessage = i18n.error_message_code_too_long;
            return false;
        }

        // 检查是否包含连续下划线
        if (code.Contains("__"))
        {
            errorMessage = i18n.error_message_double_underscore;
            return false;
        }

        // 检查是否以下划线结尾
        if (code.EndsWith("_"))
        {
            errorMessage = i18n.error_message_ends_with_underscore;
            return false;
        }

        return true;
    }
    #endregion
}
